#pragma once

#include <iostream>
#include <memory>

#include "Socket.hpp"
#include "Connection.hpp"
#include "Reactor.hpp"

using namespace socket_ns;

class Listener
{
public:
    Listener(uint16_t port)
        : _port(port), _listensock(std::make_unique<TcpSocket>())
    {
        _listensock->BuildListenSocket(_port);
    }

    int ListenSockfd()
    {
        return _listensock->Sockfd();
    }

    // 当有新连接到来，让listen连接调用Accepter函数来接收新连接并添加到Reactor中
    // 因为Reactor是ET模式，所以要把所有的连接全都获取，要进行循环获取链接。
    // 当Reactor发现事件就绪，进行事件派发时，采用的是回调对应的connection方法，调用的是对应的方法，所以还需要把链接传进去
    // 对于Accepter也是一样，因为Accepter本质也是处理读写事件的函数调用

    void Accepter(Connection* conn)
    {
        while (true)
        {

            errno = 0; // 初始化，避免下面的code受影响
            InetAddr addr;
            int code = 0; // 用来接收errno的
            int sockfd = _listensock->Accepter(&addr, &code);
            if (sockfd > 0)
            {
                // 获取链接成功，将链接添加进Reactor中
                LOG(INFO, "获取连接成功, 客户端: %s:%d, sockfd: %d\n", addr.Ip().c_str(), addr.Port(), sockfd);
                conn->_R->AddConnection(sockfd, EPOLLIN | EPOLLET, addr, NormalConnection);
            }
            else
            {
                if (code == EWOULDBLOCK)        // 读完了，套接字在非阻塞状态下读到为空时errno这样返回。
                {
                    LOG(INFO, "底层连接全部获取完毕\n");
                    break;
                }
                else if (code == EINTR)        // 被系统信号中断，接着读
                {
                    continue;
                }
                else
                {
                    LOG(ERROR, "获取连接失败.!\n"); //读失败
                    break;
                }
            }
        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensock;
};